#include "device_uart.h"
#include "FreeRTOS.h"
#include "semphr.h"

#define UART_RX_QUEUE_LEN 100

struct UART_Device g_stm32_uart1;

struct UART_Data = {
    UART_HandleTypeDef *handle;
    SemaphoreHandle_t  xTxSem;
	QueueHandle_t xRxQueue;
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    struct UART_Data *data;
    
    if(huart == &huart1)    
    {
        data = g_stm32_usart1.priv_data;
        
        /* Release semaphore. */
        xSemaphoreGiveFromISR(data->xTxSem, NULL);
    }
    
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(huart);
  /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_UART_RxCpltCallback could be implemented in the user file
   */
}

static int stm32_uart_init(struct UART_Device * pDev, int baud, int datas, char parity, int stop)
{
    struct UART_Data *data = pDev->priv_data;
    
    data->xTxSem = xSemaphoreCreateBinary();
	data->xRxQueue = xQueueCreate(UART_RX_QUEUE_LEN, 1)
    return 0;
}

static int stm32_uart_send(struct UART_Device * pDev, uint8_t *datas, int len, int timeout_ms)
{
    struct UART_Data *data = pDev->priv_data;
    
    /* Just to trigger an interrupt */
    HAL_UART_Transmit_IT(UART_HandleTypeDef *(pDev->priv_data), datas, len);
    
    /* Wait until the transmission is complete. */
    if(pdTRUE == xSemaphoreTake(data->xTxSem, timeout_ms))
    {
        return 0;
    }
    else
    {
        return -1;
    }
}

static int stm32_uart_recv(struct UART_Device * pDev, uint8_t *data, int timeout_ms)
{
	struct UART_Data *data = pDev->priv_data;

    if(pdPASS == xQueueReceive(data->xRxQueue, data, timeout_ms))
    {
		return 0;
	}
	else
	{
		return -1;
	}
	
    /* Read data from the queue. */
	HAL_UART_Receive_IT();
	
    return 0;
}

static struct UART_Data g_stm32_uart1_data = {
    &huart1,

}


struct UART_Device g_stm32_uart1 = {
    "stm32_uart1",
    stm32_uart_init,
    stm32_uart_send,
    stm32_uart_recv,
    &g_stm32_uart1_data,
};

struct UART_Device g_stm32_uart2 =
{
    "stm32_uart1",
    stm32_uart_init,
    stm32_uart_send,
    stm32_uart_recv,
    &huart2,
};
